<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { useLexicalComposer } from 'lexical-vue'
import { $getSelection, $isRangeSelection, $isTextNode } from 'lexical'
import { NModal } from 'naive-ui'
import ShortcutList from './ShortcutList.vue'
import ManageShortcutsModal from './ManageShortcutsModal.vue'
import AddEditShortcutModal from './AddEditShortcutModal.vue'

interface ShortcutCommand {
  name: string
  content: string
}

const editor = useLexicalComposer()

const isShortcutMenuVisible = ref(false)
const shortcutCommands = ref<ShortcutCommand[]>([
  { name: '姓名', content: '用户姓名' },
  { name: '邮箱', content: '用户邮箱' },
  { name: '电话', content: '用户电话' },
  { name: '地址', content: '用户地址' },
  ...Array(10).fill({ name: '地址', content: '用户地址' })
])

const shortcutMenuAnchor = ref<HTMLElement | null>(null)
const isManageModalVisible = ref(false)
const isAddCommandModalVisible = ref(false)
const editingCommandIndex = ref(-1)
const newCommand = ref({ name: '', content: '' })
const selectedCommandIndex = ref(0)

function handleKeyDown(event: KeyboardEvent) {
  if (!isShortcutMenuVisible.value) return
  switch (event.key) {
    case 'Escape':
      event.preventDefault()
      isShortcutMenuVisible.value = false
      break
    case 'ArrowDown':
      event.preventDefault()
      selectedCommandIndex.value = (selectedCommandIndex.value + 1) % shortcutCommands.value.length
      break
    case 'ArrowUp':
      event.preventDefault()
      selectedCommandIndex.value =
        (selectedCommandIndex.value - 1 + shortcutCommands.value.length) %
        shortcutCommands.value.length
      break
    case 'Enter':
      event.preventDefault()
      event.stopPropagation()
      insertContent(shortcutCommands.value[selectedCommandIndex.value].content)
      break
  }
}

function insertContent(content: string) {
  editor.update(() => {
    const selection = $getSelection()
    if ($isRangeSelection(selection)) {
      const anchorNode = selection.anchor.getNode()
      if ($isTextNode(anchorNode)) {
        const textContent = anchorNode.getTextContent()
        const cursorPosition = selection.anchor.offset
        const newTextBefore = textContent.slice(0, cursorPosition - 1)
        const newTextAfter = textContent.slice(cursorPosition)
        anchorNode.setTextContent(newTextBefore + content + newTextAfter)
        selection.setTextNodeRange(
          anchorNode,
          cursorPosition - 1 + content.length,
          anchorNode,
          cursorPosition - 1 + content.length
        )
      }
    }
    isShortcutMenuVisible.value = false
  })
}

function checkForTrigger() {
  editor.update(() => {
    const selection = $getSelection()
    if ($isRangeSelection(selection)) {
      const anchorNode = selection.anchor.getNode()
      if ($isTextNode(anchorNode)) {
        const textContent = anchorNode.getTextContent()
        const cursorPosition = selection.anchor.offset
        if (cursorPosition > 0 && textContent[cursorPosition - 1] === '/') {
          isShortcutMenuVisible.value = true
          setTimeout(updateShortcutMenuPosition, 5)
        } else {
          isShortcutMenuVisible.value = false
        }
      } else {
        isShortcutMenuVisible.value = false
      }
    } else {
      isShortcutMenuVisible.value = false
    }
  })
}

function updateShortcutMenuPosition() {
  editor.getEditorState().read(() => {
    const selection = $getSelection()
    if ($isRangeSelection(selection)) {
      const domSelection = window.getSelection()
      if (domSelection && domSelection.rangeCount > 0) {
        const range = domSelection.getRangeAt(0)
        const rect = range.getBoundingClientRect()
        if (shortcutMenuAnchor.value) {
          shortcutMenuAnchor.value.style.top = `${rect.bottom}px`
          shortcutMenuAnchor.value.style.left = `${rect.left}px`
          shortcutMenuAnchor.value.style.display = 'block'
        }
      }
    }
  })
}

function openManageModal() {
  isManageModalVisible.value = true
}

function addCommand(command: ShortcutCommand) {
  if (editingCommandIndex.value === -1) {
    shortcutCommands.value.push(command)
  } else {
    shortcutCommands.value[editingCommandIndex.value] = command
    editingCommandIndex.value = -1
  }
  isAddCommandModalVisible.value = false
}

function editCommand(index: number) {
  editingCommandIndex.value = index
  newCommand.value = { ...shortcutCommands.value[index] }
  isAddCommandModalVisible.value = true
}

function removeCommand(index: number) {
  shortcutCommands.value.splice(index, 1)
}

onMounted(() => {
  editor.registerUpdateListener(({ editorState }) => {
    editorState.read(() => {
      checkForTrigger()
    })
  })
  document.addEventListener('keydown', handleKeyDown, true)
})

onUnmounted(() => {
  document.removeEventListener('keydown', handleKeyDown, true)
})
</script>

<template>
  <div ref="shortcutMenuAnchor" v-show="isShortcutMenuVisible" class="shortcut-menu relative">
    <ShortcutList
      :commands="shortcutCommands"
      :selectedCommandIndex="selectedCommandIndex"
      @insert="insertContent"
      @manage="openManageModal"
      @update:selectedCommandIndex="selectedCommandIndex = $event"
    />
  </div>
  <NModal v-model:show="isManageModalVisible">
    <ManageShortcutsModal
      :commands="shortcutCommands"
      @edit="editCommand"
      @remove="removeCommand"
      @add="isAddCommandModalVisible = true"
    />
  </NModal>
  <NModal v-model:show="isAddCommandModalVisible">
    <AddEditShortcutModal
      :command="newCommand"
      :is-editing="editingCommandIndex !== -1"
      @save="addCommand"
      @cancel="isAddCommandModalVisible = false"
    />
  </NModal>
</template>

<style scoped>
.shortcut-menu {
  position: fixed;
  display: none;
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  box-shadow:
    0 4px 6px -1px rgba(0, 0, 0, 0.1),
    0 2px 4px -1px rgba(0, 0, 0, 0.06);
  z-index: 1000;
  min-width: 120px;
  overflow-y: auto;
}
</style>
